Skip to content

Add A2A (Agent-to-Agent) protocol support#217

Open
minorun365 wants to merge 2 commits intoaws:mainfrom
minorun365:feature/a2a-protocol-support
Open

Add A2A (Agent-to-Agent) protocol support#217
minorun365 wants to merge 2 commits intoaws:mainfrom
minorun365:feature/a2a-protocol-support

Conversation

@minorun365
Copy link

Summary

This PR adds support for the A2A (Agent-to-Agent) protocol, enabling agents to communicate with each other using the JSON-RPC 2.0 protocol.

New Features

  • BedrockAgentCoreA2AApp: A Starlette-based application class for hosting A2A agents
  • AgentCard & AgentSkill: Models for describing agent capabilities
  • @entrypoint decorator: For defining message handlers
  • JSON-RPC 2.0 support: Standard A2A protocol implementation on port 9000

New Files

  • src/bedrock_agentcore/runtime/a2a_app.py - Main A2A application class
  • src/bedrock_agentcore/runtime/a2a_models.py - A2A data models
  • tests/bedrock_agentcore/runtime/test_a2a_app.py - Unit tests for A2A app
  • tests/bedrock_agentcore/runtime/test_a2a_models.py - Unit tests for A2A models

Usage Example

from bedrock_agentcore.runtime import AgentCard, AgentSkill, BedrockAgentCoreA2AApp

agent_card = AgentCard(
    name="My Agent",
    description="A helpful assistant",
    version="1.0.0",
    skills=[AgentSkill(id="qa", name="Q&A", description="Answer questions")],
)

app = BedrockAgentCoreA2AApp(agent_card=agent_card)

@app.entrypoint
async def handle_message(request, context):
    user_text = request.params.get("message", {}).get("parts", [{}])[0].get("text", "")
    return {"artifacts": [{"parts": [{"kind": "text", "text": f"Response to: {user_text}"}]}]}

if __name__ == "__main__":
    app.run()

Test Plan

  • All 54 unit tests pass
  • Linter checks pass
  • Tested locally with curl commands
  • Deployed to AgentCore Runtime and verified working

- Add BedrockAgentCoreA2AApp class for hosting A2A agents
- Add A2A models (AgentCard, AgentSkill, JsonRpcRequest/Response, etc.)
- Add @entrypoint decorator for message handling
- Support JSON-RPC 2.0 protocol on port 9000
- Export A2A classes from runtime module
- Add comprehensive unit tests (54 tests)
@Moophic
Copy link

Moophic commented Mar 2, 2026

@sundargthb,
Can we get this beautiful PR reviewed and merged please?

from urllib.parse import quote


class JsonRpcErrorCode(int, Enum):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the codes here match this page but contradicts with the A2A Protocol contract page.. need to check the valid range

return JSONResponse(card_dict)
except Exception as e:
self.logger.exception("Failed to serve Agent Card")
return JSONResponse({"error": str(e)}, status_code=500)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

str(e) is passed directly into the JSON-RPC error response. ... internal exception details (paths, library errors, connection strings) can reach external agents ? the HTTP app.py has the same str(e) pattern — so this isn't new to the PR, it's consistent with existing code. But A2A is explicitly cross-organizational (A2A Enterprise Features)

self.logger.exception("Request failed (%.3fs)", duration)
return self._jsonrpc_error_response(
body.get("id") if "body" in dir() else None,
JsonRpcErrorCode.INTERNAL_ERROR,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as _handle_agent_card..

)


class A2ARequestContextFormatter(logging.Formatter):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP app has @async_task, add_async_task()/complete_async_task(), and force_ping_status()/clear_forced_ping_status(). Without these, developers can't signal HealthyBusy during long-running agent workflows, which means the runtime may incorrectly scale down or over-route. Can either finish the port from app.py or remove the unused attributes/logic

minorun365 pushed a commit to minorun365/bedrock-agentcore-sdk-python that referenced this pull request Mar 12, 2026
Add missing A2A protocol standard error codes (-32001 to -32007) alongside
existing AgentCore Runtime error codes (-32501 to -32505). The two sets serve
different layers: protocol-level (task management) vs infrastructure-level
(throttling, resource management). Added corresponding tests.

Addresses review feedback on PR aws#217 regarding error code alignment between
A2A protocol spec and AWS AgentCore documentation.

https://claude.ai/code/session_01Fnc4LHzBPBej7FK7ooT2La
@minorun365 minorun365 requested a review from a team March 12, 2026 06:48
- Remove unused imports (JsonRpcRequest, pytest) in tests
- Initialize body=None before try block; replace `"body" in dir()` with
  `body is not None`
- Add `isinstance(body, dict)` guard so non-object JSON payloads return
  INVALID_REQUEST (-32600) instead of INTERNAL_ERROR (-32603)
- Use `_convert_to_serializable()` / `_safe_serialize_to_json_string()`
  for both streaming and non-streaming paths so dataclass helpers
  (A2AArtifact, etc.) serialize correctly
- Fall back to `request.base_url` when AGENTCORE_RUNTIME_URL is unset so
  the agent card always contains a reachable URL
- Add tests for dataclass serialization (sync + streaming) and
  non-object payload rejection
@minorun365
Copy link
Author

@sundargthb Thanks for your review! Fixed it.

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 85.48813% with 55 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@52bc194). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/bedrock_agentcore/runtime/a2a_app.py 81.22% 34 Missing and 12 partials ⚠️
src/bedrock_agentcore/runtime/a2a_models.py 93.18% 3 Missing and 6 partials ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #217   +/-   ##
=======================================
  Coverage        ?   90.38%           
=======================================
  Files           ?       44           
  Lines           ?     4420           
  Branches        ?      664           
=======================================
  Hits            ?     3995           
  Misses          ?      240           
  Partials        ?      185           
Flag Coverage Δ
unittests 90.38% <85.48%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants